﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Von.Web.Framework;
using Von.Web.Models;
using Von.Web.Structs;
using Von.Web.Tasks;

namespace Von.Web.Controllers
{
    public class HomeController : WebControllerBase
    {
        #region "inherited properties"
        private IEmailSender emailSender = null;
        public override ApplicationDefinationBase App => Statement.App;
        /// <summary>
        /// 构造函数，实例化了日志工具
        /// </summary>
        /// <param name="logger">日志实例</param>
        public HomeController(IEmailSender EmailSender)
        {
            emailSender = EmailSender;
        }
        #endregion
        private static int homePageIdx = 1;

        public IActionResult StatusCodePage(int? statusCode, [FromServices] ICompositeViewEngine compositeViewEngine)
        {
            bool viewExists = statusCode.HasValue && compositeViewEngine.FindView(ControllerContext, statusCode.Value.ToString(), true).Success;
            return viewExists ? View(statusCode.Value.ToString()) : View("Default");
        }
        public IActionResult Index()
        {
            ViewBag.DisplaySpliter = true;
            if (string.IsNullOrEmpty(Runtime.HomePage) || Runtime.HomePage.Equals("/Home/Index", StringComparison.OrdinalIgnoreCase))
                return View();
            else
            {
                if (UserInfo != null)
                {
                    string defaultPage = UserInfo.GetSubsidiary("DefaultPage").Result;
                    if (!string.IsNullOrEmpty(defaultPage)) return Redirect(defaultPage);
                }
                string homePage = Runtime.HomePage;
                IViewEngine viewEngine = HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
                homePage = string.Format(Runtime.HomePage, homePageIdx++);
                if (homePageIdx > 3) homePageIdx = 1;
                return Redirect(homePage);
            }
        }
        [Action("{81E437E0-D92F-4406-89FC-4970028C1369}", "主页管理", "更换皮肤", EControlKind.CK_Ajax)]
        public async Task<ExecuteResult> ChangeSkin(JsonStr param)
        {
            if (param.Json["skin"] == null)
                return ExecuteResult.Failed("", "0003", "参数错误系统拒绝执行！");
            //switch (param.Json["skin"].ToString().ToLower())
            //{
            //    case "james": Runtime.defaultLayoutName = "/Views/Shared/_james_layout.cshtml"; Runtime.adminLayoutName = "/Views/Shared/_james_admin.cshtml"; break;
            //    case "lte": Runtime.defaultLayoutName = "/Views/Shared/_LTE_layout.cshtml"; Runtime.adminLayoutName = "/Views/Shared/_LTE_admin.cshtml"; break;
            //    case "org": Runtime.defaultLayoutName = "/Views/Shared/_default_layout.cshtml"; Runtime.adminLayoutName = "/Views/Shared/_default_admin.cshtml"; break;
            //    case "ms": Runtime.defaultLayoutName = "/Views/Shared/_ms_layout.cshtml"; Runtime.adminLayoutName = "/Views/Shared/_ms_admin.cshtml"; break;
            //}
            return ExecuteResult.Success(true);
        }
        public IActionResult Privacy()
        {
            return View();
        }
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error(ErrorViewModel err)
        {
            err.RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
            return View(err);
        }
        public IActionResult Test()
        {
            return View();
        }

        #region "HtmlContent"
        private async Task<List<HtmlCatalogTree>> loadChildrenHtmlCatalog(HtmlCatalogTask task, int ID, bool hasChildren)
        {
            List<HtmlCatalogTree> list = await task.ListByPID<HtmlCatalogTree>(ID);  //原有功能
            if (hasChildren)
                foreach (HtmlCatalogTree m in list)
                    m.children = await loadChildrenHtmlCatalog(task, m.ID, true);
            return list;
        }
        private async Task<List<Dictionary<string, object>>> GetCatalogAndContent(int CatalogIdx)
        {
            List<Dictionary<string, object>> tree = Statement.Accession.ListFromDB(new DBSelection()
            {
                TableCode = "HtmlContent",
                Fields = "ID,HtmlName AS KeyName,CatalogIdx AS PID,ID AS CID",
                conditions = new DBCondition[]
                {
                        new DBCondition(){
                            FieldName = "CatalogIdx",
                            Data=CatalogIdx,
                            Condition=EDBCondition.等于
                        }
                }
            });
            List<Dictionary<string, object>> catalogTree = Statement.Accession.ListFromDB(new DBSelection()
            {
                TableCode = "HtmlCatalog",
                Fields = "ID,CatalogName AS KeyName,PID,'0' AS CID",
                conditions = new DBCondition[]
                {
                        new DBCondition(){
                            FieldName = "PID",
                            Data=CatalogIdx,
                            Condition=EDBCondition.等于
                        }
                }
            });
            foreach(var catalog in catalogTree)
            {
                if(tree != null) tree.Add(catalog);
                List<Dictionary<string, object>> treeChildren = await GetCatalogAndContent(int.Parse(catalog["ID"].ToString()));
                if (treeChildren != null)
                    catalog.Add("children", treeChildren);
            }
            if (tree == null) return catalogTree;
            return tree;
        }
        public async Task<IActionResult> HtmlContent(string ID, int? style)
        {
            #region "Setting of style"
            if (style == null) style = 0;
            ViewBag.displayPublishedInfo = (style & 0x1) > 0;
            ViewBag.displayAuthorInfo = (style & 0x2) > 0;
            ViewBag.displaySourceInfo = (style & 0x4) > 0;
            ViewBag.displayFontInfo = (style & 0x8) > 0;
            ViewBag.displayShareInfo = (style & 0x10) > 0;
            ViewBag.displaySummaryInfo = (style & 0x20) > 0;
            ViewBag.displayCommentInfo = (style & 0x40) > 0;
            #endregion
            HtmlContentTask contentTask = new HtmlContentTask();
            int cid = 0;
            #region "Display content of html"
            if (int.TryParse(ID, out cid))
            {
                HtmlContentModel model0 = await contentTask.GetByHtmlContent<HtmlContentModel>(cid);
                model0.Summary = await contentTask.GetSummary(cid);
                model0.Content = await contentTask.GetContent(cid);
                return View(model0);
            }
            #endregion
            HtmlCatalogTask catalogTask = new HtmlCatalogTask();
            string[] cts = ID.Split('.');
            #region "Display html and subcatalog, Catalog=<CatalogIdx>"
            if (cts[0].Equals("Catalog", StringComparison.OrdinalIgnoreCase))
            {
                List<Dictionary<string, object>> tree = await GetCatalogAndContent(int.Parse(cts[1]));
                ViewBag.Catalog = tree;
                if (!string.IsNullOrEmpty(tree[0]["CID"].ToString()))
                {
                    cid = int.Parse(tree[0]["CID"].ToString());
                    HtmlContentModel model1 = await contentTask.GetByHtmlContent<HtmlContentModel>(cid);
                    model1.Summary = await contentTask.GetSummary(cid);
                    model1.Content = await contentTask.GetContent(cid);
                    return View(model1);
                }
                return View(null);
            }
            #endregion
            #region "Display html with HtmlName by level, HtmlName=<CatalogName>[.<CatalogName>].<HtmlName>"
            int PID = 0; HtmlCatalogInfo info;
            for (int i = 0; i < cts.Length - 1; i++)
            {
                info = await catalogTask.FindHtmlCatalog(PID, cts[i]);
                if (info == null) return View(null);
                PID = info.ID;
            }
            HtmlContentModel model = await contentTask.FindHtmlContent<HtmlContentModel>(PID, cts[cts.Length - 1]);
            if (model == null) return View(null);
            model.Summary = await contentTask.GetSummary(model.ID);
            model.Content = await contentTask.GetContent(model.ID);
            return View(model);
            #endregion
        }
        [Action("{48DB14F1-1BE5-415E-AF69-5FC6C1E56220}", "主页管理", "提交评论", EControlKind.CK_Ajax)]
        public async Task<ExecuteResult> CommentPublish(JsonStr param)
        {
            CommentTask task = new CommentTask();
            CommentInfo info = new CommentInfo()
            {
                Kind = WebUtility.HtmlDecode(param.Json["Kind"].ToString()),
                LinkIdx = param.Json["LinkIdx"].ToString(),
                Evaluation = param.Json.Value<int>("Evaluation"),
                Publishedate = DateTime.Now,
                Publisher = IsLogin ? UserInfo.ID : Guid.Empty,
                Email = IsLogin ? UserInfo.Email : (param.Json["Email"] == null ? "" : param.Json["Email"].ToString()),
                Concern = param.Json["Concern"] == null ? false : param.Json.Value<int>("Concern") > 0,
                Support = param.Json["Support"] == null ? false : param.Json.Value<int>("Support") > 0,
                Oppose = param.Json["Oppose"] == null ? false : param.Json.Value<int>("Oppose") > 0,
                ReplyDate = Von.Library.Consts.MinDBDate,
                Replyer = Guid.Empty,
                Content = param.Json["Content"].ToString(),
                ReplyContent = ""
            };
            if (await task.Add(info))
            {
                var setting = Runtime.Portal.AppSetting["CommentAnswer"][info.Kind];
                if (setting == null) Log.Warn(info.Kind + "评论答复人邮箱没有设置，请在应用管理中Settings的CommentAnswer，设置" + info.Kind + ":xxx@xxx.comn内容。");
                else
                {
                    string mailContent = "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>读者评论</title>" +
                        "</head><body><style>.well {min-height: 20px; padding: 19px; margin-bottom: 20px; background-color: #f5f5f5;" +
                        "border: 1px solid #e3e3e3;border-radius: 4px;-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.05);box-shadow: inset 0 1px 1px rgba(0,0,0,.05);}</style>" +
                        "<p>有读者对《<a href=\"" + HttpContext.Request.Host.ToString() + info.LinkIdx + "\" >" + WebUtility.HtmlDecode(param.Json["Summary"].ToString()) + "</a>》进行了评论</p><p>" +
                        string.Format("基本评论（评分:{0}，{1}{2}{3}）评论内容如下：", info.Evaluation, info.Concern ? "关注了本文档，" : "", info.Support ? "表达了支持，" : "", info.Oppose ? "表达了反对" : "") + "</p><div class=\"well\">" +
                        info.Content + "</div><a href=\"" + HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.ToString() + "/admin/commentManage/" + info.ID.ToString() + "\">点击这里进行回复</a></body></html>";

                    //string mailContent = string.Format("评价结果（评分:{0}，{1}{2}{3}）内容如下：\r\n{4}\r\n点击下面链接可对评论进行回复：{5}",
                    //    info.Evaluation, info.Concern ? "关注了本文档，" : "", info.Support ? "表达了支持，" : "", info.Oppose ? "表达了反对" : "",
                    //    info.Content, HttpContext.Request.Host.ToString() + "/admin/commentManage/" + info.ID.ToString());
                    emailSender.SendMailAsync(setting.ToString(), "有人评价了" + info.Kind + "的《" + WebUtility.HtmlDecode(param.Json["Summary"].ToString()) + "》", mailContent);
                }
                return ExecuteResult.Success(info);
            }
            return Failed("007");
        }
        private async Task saveUploadFile(Stream src, string filename)
        {
            using (FileStream fs = System.IO.File.Create(filename))
            {
                src.Position = 0;
                src.CopyTo(fs);
                fs.Close();
            }
        }
        [Action("{552DDE45-5726-42E1-9916-8D0B85B134C8}", "获取文档内容", "文档查询", EControlKind.CK_View)]
        public async Task<ExecuteResult> GetHtmlContent(JsonStr param)
        {
            if (param.Json["ID"] == null)
                return Failed("0003", "参数错误系统拒绝执行！");
            int ID = param.Json.Value<int>("ID");
            HtmlContentTask task = new HtmlContentTask();
            HtmlContentModel model = await task.GetByHtmlContent<HtmlContentModel>(ID);
            if (model == null) ExecuteResult.Success(null);
            model.Summary = await task.GetSummary(model.ID);
            model.Content = await task.GetContent(model.ID);
            return ExecuteResult.Success(model);
        }
        #endregion
        /// <summary>图片上传</summary>
        /// <param name="env"></param>
        /// <returns></returns>
        public async Task<IActionResult> UploadImageUrl(string ID)
        {
            string[] uploadPath = ID.Split(new char[] { '-', '&', '=', '?' });
            string callback = Request.Query["CKEditorFuncNum"];
            var file = Request.Form.Files[0];
            string fileExt = file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
            string guidFilename = Guid.NewGuid().ToString() + "." + fileExt;
            string bowerPath = "/" + String.Join("/", uploadPath) + "/" + guidFilename;//获取到图片保存的路径，这边根据自己的实现
            string savePath = Directory.GetCurrentDirectory() + "\\wwwroot\\" + String.Join("\\", uploadPath) + "\\";
            if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath);
            savePath += guidFilename;
            using (MemoryStream src = new MemoryStream())
            {
                file.CopyTo(src);
                if (!fileExt.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))
                    using (MemoryStream dest = new MemoryStream())
                    {
                        Von.Library.VonGraphic.ConvertImgStream(src, dest, ImageFormat.Jpeg);
                        await saveUploadFile(dest, savePath);
                        dest.Close();
                    }
                else
                    await saveUploadFile(src, savePath);
                src.Close();
            }
            //服务器返回JavaScript脚本
            string result = $"<script type=\"text/javascript\">window.parent.CKEDITOR.tools.callFunction(\"{callback}\", \"{ bowerPath }\", \"\");</script>";
            Response.ContentType = "text/html;charset=UTF-8";
            return Json(new
            {
                uploaded = 1,
                fileName = guidFilename,
                url = bowerPath
            }); //Content(result);
        }
        [Action("{427A3A3E-A158-426A-86F6-D10ED44B25F2}", "主页管理", "提取行政区划列表", EControlKind.CK_Ajax)]
        public async Task<ExecuteResult> ListAdministrativeDistrictRoot()
        {
            AdministrativeDistrictTask task = new AdministrativeDistrictTask();
            return ExecuteResult.Success(await task.List(1));
        }
        [Action("{24CE7824-8748-4855-8F0D-1464A255EBC4}", "主页管理", "提取行政区划列表", EControlKind.CK_Ajax)]
        public async Task<ExecuteResult> ListAdministrativeDistrict(JsonStr param)
        {
            AdministrativeDistrictTask task = new AdministrativeDistrictTask();
            return ExecuteResult.Success(await task.List(param.Json["Code"].ToString()));
        }
        [Action("{0ADC7958-55B7-4969-B624-0127CEED8284}", "主页管理", "大屏展示", EControlKind.CK_View)]
        public async Task<IActionResult> ScreenView(int ID)
        {
            await WriteLog(ELogLevel.info, "ScreenItemManage", "View of /Von/Web/ScreenView");
            //Log.InfoFormat("User {0} access /Join/Web/ScreenView", UserInfo.ID);
            ViewBag.Screen = Statement.Accession.GetFromDB(new DBSelection()
            {
                TableCode = "Screen",
                Fields = "ID,ScreenName,Width,Height,Style",
                conditions = new DBCondition[] { new DBCondition("ID", EDBCondition.等于, ID)
            } });

            List<Dictionary<string, object>> items = Statement.Accession.ListFromDB(new DBSelection()
            {
                TableCode = "ScreenItem",
                Fields = "ID,ItemType,ScreenIdx,PosX,PosY,Width,Height,UpdateUnit,UpdateTime,Style,Setting,SampleData,DisplayOrder",
                conditions=new DBCondition[] { new DBCondition("ScreenIdx", EDBCondition.等于, ID) }
            });
            StringBuilder sb = new StringBuilder("var items = [];");
            foreach (var d in items)
            {
                var cmp = Runtime.GetComponent(d["ItemType"].ToString());
                ScreenItemModel m = new ScreenItemModel();
                m.Import(d);
                sb.Append(cmp.Run(m));
            }
            ViewBag.components = sb.ToString();
            return View();
            //return View(System.Web.HttpUtility.HtmlEncode());
        }
        #region "HtmlCatalogView"
        [Action("{CBE65D27-627C-424F-BA76-29FB6A2004F1}", "文档管理", "文档查询", EControlKind.CK_View)]
        public async Task<IActionResult> HtmlCatalogView()
        {
            return View();
        }
        [Action("{F4230036-B6E5-4373-9D8C-1DC16C72A0F6}", "文档管理", "预览分类文件列表", EControlKind.CK_Ajax)]
        [Authorize]
        public async Task<ExecuteResult> ListHtmlContent(JsonStr param)
        {
            if (param.Json["CatalogIdx"] == null)
                return Failed("0003", "参数错误系统拒绝执行！");
            int ID = param.Json.Value<int>("CatalogIdx");
            HtmlContentTask task = new HtmlContentTask();
            List<HtmlContentInfo> list = await task.ListByCONTENT_REF_HTMLCATALOG<HtmlContentInfo>(ID, 0, "发布");
            return ExecuteResult.Success(list);
        }
        [Action("{98B4E7D8-9C17-4D7D-A512-DA0C3AC9E6DC}", "文档管理", "搜索文件列表", EControlKind.CK_Ajax)]
        [Authorize]
        public async Task<ExecuteResult> SearchHtmlContent(JsonStr param)
        {
            WriteLog(ELogLevel.info, "SearchHtmlContent", "Access to /Home/SearchHtmlContent");
            return ExecuteResult.Success(Statement.Accession.ListFromDB(
                JObject.Parse(@"{
                    TableCode:""HtmlContent"",Fields:""ID,HtmlName,Title,Autor,Src,Linker,Keyword,Tags,Summary"",
                    conditions:" + param.data + "}")));
        }
        #endregion
    }
}
